#version 450 core

out vec4 fragColor;

layout(std140, binding = 0) uniform PerDraw
{
    mat4 modelMatrix;
    mat4 viewMatrix;
    mat4 projMatrix;
    vec3 cameraPos;
} perDraw;

layout(std140, binding = 1) uniform DirLight
{
    vec3 color;
    vec3 direction;
} dirLight;

layout(std140, binding = 2) uniform PointLight
{
    vec3 color;
    vec3 position;
    float range;
} pointLight;

layout(std140, binding = 3) uniform SpotLight
{
    vec3 color;
    float range;
    vec3 position;
    float innerCos;
    vec3 direction;
    float outerCos;
} spotLight;

layout(std140, binding = 10) uniform Material
{
    vec3 diffuseColor;
    vec3 specularColor;
    float specularStrength;
} material;

layout(binding = 0) uniform sampler2D diffuseTex;
layout(binding = 1) uniform sampler2D specularTex;

in Varyings
{
    vec3 positionWS;
    vec3 normalWS;
    vec2 uv;
} i;

// 简单的光照模型Blin-Phong
vec3 Lighting(vec3 N, vec3 L, vec3 V, vec3 P, vec3 lightColor)
{
    // diffuse
    vec3 diffuse = lightColor * clamp(dot(N, L), 0.0, 1.0) * texture(diffuseTex, i.uv).rgb;//material.diffuseColor;
    // specular
    // 两种方法，一种直接通过反射光求高光，另一种通过半程向量近似计算
    // 1. reflect
    vec3 R = reflect(-L, N);
    vec3 specular = texture(specularTex, i.uv).rgb * pow(clamp(dot(V, R), 0.0, 1.0), material.specularStrength);
    // 2. half-vector
    //    vec3 H = normalize((L + V) * 0.5);
    //    vec3 specular = material.specularColor * pow(clamp(dot(N, H), 0.0, 1.0), material.specularStrength);

    return diffuse + specular;
}

void main()
{
    // 多光源，实际上就是每种光照计算的结果叠加，这是光的特性
    // 最终颜色
    vec3 color = vec3(0.0);

    // position
    vec3 P = i.positionWS;
    // normal
    vec3 N = normalize(i.normalWS);
    // camera dir
    vec3 V = normalize(perDraw.cameraPos - P);

    // Direction Light
    // light dir
    vec3 L = normalize(dirLight.direction);
    color += Lighting(N, L, V, P, dirLight.color);

    // Point Light
    // 点光源有个有效范围range，超出范围的就不计算光照了
    // 在范围内的，光强度按照距离的平方衰减
    vec3 disV = pointLight.position - P;
    float dis2 = dot(disV, disV);
    L = normalize(disV);
    float decay = clamp(1.0 - dis2 / (pointLight.range * pointLight.range), 0.0, 1.0);
    color += Lighting(N, L, V, P, pointLight.color) * decay * decay;

    // Spot Light
    // 内角以内的正常照亮
    // 内角到外角的需要衰减（用平方衰减）
    // 以外的没光照
    // 只有range距离内的才有光照
    disV = spotLight.position - P;
    dis2 = dot(disV, disV);
    L = normalize(disV);
    float cosTheta = dot(spotLight.direction, L);
    float fac = 1.0 - clamp((cosTheta - spotLight.outerCos) / (spotLight.innerCos - spotLight.outerCos), 0.0, 1.0);
    decay = 1.0 / (1.0 + 5.0 * fac * fac);
    color += Lighting(N, L, V, P, spotLight.color) * decay * step(dis2, spotLight.range * spotLight.range);

    fragColor = vec4(color, 1.0);
}
